﻿using System;
using System.IO;
using System.Runtime.InteropServices;
using UnityEngine;

namespace KEngine
{
    public class ConsoleWindow : MonoBehaviour
    {
        //public delegate void InputText( string strInput );  
//        public event System.Action<string,LogLevel> OnInputText;  
        public string inputString;

        private void Awake()
        {
            Initialize();
            SetTitle("unity additional console by hollowJ");
        }

        public void ClearLine()
        {
            //System.Text.Encoding test = Console.InputEncoding;  
            Console.CursorLeft = 0;
            Console.Write(new String(' ', Console.BufferWidth));
            Console.CursorTop--;
            Console.CursorLeft = 0;
        }

        public void RedrawInputLine()
        {
            if (inputString.Length == 0) return;

            if (Console.CursorLeft > 0)
                ClearLine();

            Console.ForegroundColor = ConsoleColor.Green;
            Console.Write(inputString);
        }

        internal void OnBackspace()
        {
            if (inputString.Length < 1) return;

            inputString = inputString.Substring(0, inputString.Length - 1);
            RedrawInputLine();
        }

        internal void OnEscape()
        {
            //按Esc键清屏
            Console.Clear();
            ClearLine();
            inputString = "";
        }

        internal void OnEnter()
        {
            ClearLine();
            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine("> " + inputString);

            var strtext = inputString;
            inputString = "";

            OnInputText(strtext, LogLevel.Debug);
        }
        
        /**
         * 外置控制台打印唯一接口
         */
        public void OnInputText(String strtext, LogLevel logLevel)
        {
            switch (logLevel)
            {
                case LogLevel.All:
                {
                    Console.ForegroundColor = ConsoleColor.White;
                }
                    break;
                case LogLevel.Warning:
                {
                    Console.ForegroundColor = ConsoleColor.Green;
                }
                    break;
                case LogLevel.Error:
                {
                    Console.ForegroundColor = ConsoleColor.Red;
                }
                    break;
                default:
                {
                    Console.ForegroundColor = ConsoleColor.White;
                }
                    break;
            }

            Console.Write(strtext);
        }

        private void OnDestroy()
        {
            Shutdown();
        }

        public void Update()
        {
            if (!Console.KeyAvailable) return;
            var key = Console.ReadKey();

            if (key.Key == ConsoleKey.Enter)
            {
                OnEnter();
                return;
            }

            if (key.Key == ConsoleKey.Backspace)
            {
                OnBackspace();
                return;
            }

            if (key.Key == ConsoleKey.Escape)
            {
                OnEscape();
                return;
            }

        }

        TextWriter oldOutput;

        public void Initialize()
        {
            //  
            // Attach to any existing consoles we have  
            // failing that, create a new one.  
            //  
            if (!AttachConsole(0x0ffffffff))
            {
                AllocConsole();
            }

            oldOutput = Console.Out;

            try
            {
                IntPtr stdHandle = GetStdHandle(STD_OUTPUT_HANDLE);
                Microsoft.Win32.SafeHandles.SafeFileHandle safeFileHandle =
                    new Microsoft.Win32.SafeHandles.SafeFileHandle(stdHandle, true);
                FileStream fileStream = new FileStream(safeFileHandle, FileAccess.Write);
                System.Text.Encoding encoding = System.Text.Encoding.ASCII;
                StreamWriter standardOutput = new StreamWriter(fileStream, encoding);
                standardOutput.AutoFlush = true;
                Console.SetOut(standardOutput);
            }
            catch (System.Exception e)
            {
                Debug.Log("Couldn't redirect output: " + e.Message);
            }
        }

        public void Shutdown()
        {
            Console.SetOut(oldOutput);
            FreeConsole();
        }

        public void SetTitle(string strName)
        {
            SetConsoleTitle(strName);
        }

        private const int STD_OUTPUT_HANDLE = -11;

        [DllImport("kernel32.dll", SetLastError = true)]
        static extern bool AttachConsole(uint dwProcessId);

        [DllImport("kernel32.dll", SetLastError = true)]
        static extern bool AllocConsole();

        [DllImport("kernel32.dll", SetLastError = true)]
        static extern bool FreeConsole();

        [DllImport("kernel32.dll", EntryPoint = "GetStdHandle", SetLastError = true, CharSet = CharSet.Auto,
            CallingConvention = CallingConvention.StdCall)]
        private static extern IntPtr GetStdHandle(int nStdHandle);

        [DllImport("kernel32.dll")]
        static extern bool SetConsoleTitle(string lpConsoleTitle);
    }
}